
/* GCSx
** TILESETPAINT.H
**
** Tileset editing- actual paint/edit window
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#ifndef __GCSx_TILESETPAINT_H_
#define __GCSx_TILESETPAINT_H_

class TilePaintTools : public Dialog {
private:
    ToolSelect* toolSelect;
    ToolSelect* dotsSelect;
    class TilePaint* paintArea;
    class FrameWindow* myFrame;

    enum {        
        // For tool popup selections
        TOOLSELECT_NUM_TOOLS = 11,
        // Dots selection
        TOOLSELECT_NUM_DOTS = 3,
    };
    
    static const ToolSelect::ToolIconStruct toolIcons[TOOLSELECT_NUM_TOOLS];
    static const ToolSelect::ToolIconStruct dotsIcons[TOOLSELECT_NUM_DOTS];
    
    // Adjusts panel for current tool- hiding/rearranging configuration elements
    void adjustForTool();
    
    // Used to help resize preview area- this is
    // our height if preview is 0 pixels high
    int minHeight;
    
public:
    enum {
        // Color select
        ID_COLOR = 1,
        
        // Alpha blend
        ID_ALPHALABEL,
        ID_ALPHA_S,
        ID_ALPHA_N,
        
        // Tool options
        ID_ANTIALIAS, // Actually used as "Contiguous" also
        ID_TOLERANCELABEL,
        ID_TOLERANCE_S,
        ID_TOLERANCE_N,
        
        // Individual buttons
        ID_TOOL,
        ID_NEXT,
        ID_PREV,
        ID_ZOOMIN,
        ID_ZOOMOUT,
        ID_COPY,
        ID_PASTE,
        
        // Setting buttons
        ID_GRID,
        ID_DOTS,
        
        // Preview
        ID_PREVIEW,
    };

    int* toolPtr;
    int* antiAliasPtr;
    int* alphaBlendPtr;
    int* tolerancePtr;
    int* gridPtr;
    int* dotsPtr;

    TilePaintTools(class TilePaint* tPaintArea, SDL_Surface** tileSource, int* tool, int* alphaBlend, int* antiAlias, int* tolerance, int* grid, int* dots);
    ~TilePaintTools();
    
    // Creates a FrameWindow and returns, does not add self to desktop (use ->show() to do that)
    class FrameWindow* createWindowed();
    
    int event(int hasFocus, const SDL_Event* event);
    void resize(int newWidth, int newHeight, int newViewWidth = -1, int newViewHeight = -1, int fromParent = 0);
    void childModified(Window* modified);
    void tileRedraw();
    int wantsToBeDeleted() const;
    WindowSort windowSort() const;
};

class TilePaint : public Window {
private:
    FrameWindow* myFrame;
    TilePaintTools* tools;
    class ColorSelect* colorbar;
    int hover;
    int lastMouseX;
    int lastMouseY;

    int tool;
    int alphaBlend;
    int antiAlias; // Also used as "contiguous" setting
    int tolerance;
    ColorStore colors;

    TileSetEdit* tileset;
    WorldEdit* world;
    
    SDL_Surface* tile;
    int glyphWidth; // For font editing
    SDL_Surface* alphaWorkspace;
    // alpha0 = not selected, anything else = selected
    // used to store selection rectangles AND floating selection
    // size may differ from tile size
    SDL_Surface* selection;
    // Backs up selection during selection tool drags
    SDL_Surface* backupSelection; // Also (ab)used as temp storage sometimes
    // .w = 0 if we have no current selection
    // otherwise gaurunteed to not be larger than the selection surface
    Rect selectionRect;
    Rect backupSelectionRect;
    // Selection mode
    enum {
        SELECTION_OUTLINE = 0, // Draw outline only, no data
        SELECTION_OPAQUE,      // Paste/ovelay as-is
        SELECTION_ALPHA,       // Paste/overlay with alpha
    };
    int selectionMode;
    // Move selection; gaurunteed to be 0 if SELECTION_OUTLINE
    int selectionXOffs;
    int selectionYOffs;
    
    // If true, we're editing collision maps- everything refers to and
    // affects collision maps instead of tiles (including only having two colors)
    int isColl;
    
    int currentTile;
    int numTiles;
    int tileWidth;
    int tileHeight;
    int isFont;
    int pixelSize; // Only exact multiple zoom ratios
    int gridSize; // Considered part of pixel size; 0 or 1 only
    int enableGrid; // Affects gridSize to 0 or 1
    int drawDots;
   
    int cursorX;
    int cursorY;
    int hideCursor;
    int haveFocus;
    int partialFocus;
    
    // "virtual" cursor for dragging- where the cursor would be if no limits
    int virtualCursorX;
    int virtualCursorY;
    
    int toolStartX;
    int toolStartY;
    int toolLastX;
    int toolLastY;
    int toolFgBk;
    int toolActive;
    Uint32 toolColor;
    int toolAlpha;
    int toolAlias; // Used for "contiguous" setting also
    int toolTolerance;
    int toolCtrl;
    int toolAlt;
    int startToolOnMove;
    
    // Min and max x/y for pen tool, to save undo
    int toolMinX;
    int toolMinY;
    int toolMaxX;
    int toolMaxY;
    
    void refreshTile(); // Doesn't set any sort of dirty
    void applyTile();
    void applyGlyphWidth();
    
    enum {
        // Zooming
        MAX_ZOOM = 20, // Highest zoom
        MAX_ZOOMGRID = 3, // Highest zoom grid is visible
        
        // Size of glyph width pointer and margin
        GLYPH_SIZE_POINTER_HEIGHT = 5,
        GLYPH_SIZE_POINTER_MARGIN = 2,
    };

    // Move cursor, then call
    // "fgbk" is USE_FG or USE_BK.
    void startTool(int fgbk);
    void startToolSelectionDrag();
    void startToolGlyphWidthDrag();
    void modifyTool(); // Call if CTRL/ALT changes
    void dragTool(int firstTime = 0, int lastTime = 0);
    void finishTool();
    void cancelTool();

    // Dirty range
    Rect dirtyRange;

    // Set partial dirty- coordinates are in tile pixels, not zoomed pixels
    // selectionFeather, if true, will consider this a dirty rect from
    // modification of selection, which creates a slightly bigger dirty
    // area because it requires surrounding pixels to redraw also; this does
    // not need to be set for clearing of -entire- selection
    void setDirtyBox(int x1, int y1, int x2, int y2, int selectionFeather = 0);
    void setDirtyRect(const Rect& rect, int selectionFeather = 0);
    void setDirtyGlyphWidth(int x1, int x2);
    
    // Moves glyph width pointer; doesn't update tile permanently
    void setGlyphWidth(int gX);

    // Undo wrappers
    void undoStoreBlitBox(int x1, int y1, int x2, int y2) throw_Undo;
    void undoStoreBlit(int x, int y, int w, int h) throw_Undo;
    void undoStoreSelect(int x, int y, int w, int h) throw_Undo;
    void undoStoreGlyph() throw_Undo;
    
    // Clear a selection or merge a floation selection; stores undo
    void doneSelection() throw_Undo;
    // Clear selection rectangle, discard any floating selection
    void clearSelection(int storeUndo = 1) throw_Undo;
    // Take an existing outline selection and floats it; replaces
    // old data with background color;
    // Stores undo
    void floatSelection() throw_Undo;
    // Copy an outline or floating selection to clipboard, doesn't
    // affect tile or selection in any way
    void copySelection();
    // Paste clipboard as a new selection; first merges or removes
    // any existing selection
    // Stores undo
    void pasteSelection() throw_Undo;
    // Fill selection with bk color or delete a floating selection
    // Stores undo
    void deleteSelection() throw_Undo;
    // Merges a floating selection if one exists
    // Stores undo
    void mergeSelection() throw_Undo;
    // Rescan selection rectangle and update selectionRect bounding box
    void fixSelectionRect();
    // Returns true if a given tile pixel x/y is within the current selection area
    int isInSelection(int x, int y);
    
    void zoomIn();
    void zoomOut();
    
    void changeTile(int newTile);
    void changePixelSizing(int newPixelSize, int newGridSize);
    // (after this, you must load or reload tile!)
    void reloadTileStats();
    void moveCursor(int newX, int newY);
    void moveSelection(int newX, int newY);
    void mousePointer();
    void mousePointer(int mouseX, int mouseY);
    void updateTitlebar();

public:
    // Opens the window
    TilePaint(TileSetEdit* myTileset, int myTile, int myIsColl = 0) throw_File;
    ~TilePaint();
    
    // Called by tool panel to tell us to refresh
    void refresh();
    // Called by tool panel to tell us tool was selected via key hold
    void startToolIfMove();
    // Used by undo system
    void swapSelectionParameters(int& xoffs, int& yoffs, int& mode);

    int event(int hasFocus, const SDL_Event* event);
    void display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset);
    CommandSupport supportsCommand(int code) const;
    WindowType windowType() const;
    void undoNotify(int undoType, int undoItemId, int undoItemSubId, int uX, int uY, int uW, int uH);
};

#endif

